/*!
 * \file sample_core.c
 *
 * \brief 共通定义
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 共通使用的宏和结构体
 *
 * \version 1.0
 * \author jikw
 * \date 2016/2/22
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "iconv2utf8.h"
#include "frbyte_buffer.h"
#include "frct_comm.h"
#include "frreport_comm.h"
#include "frbase64.h"
#include "config.h"
#include "frservice_comm.h"
#include "sample_core.h"

typedef struct __st_L7session_http_private {
    unsigned long ul_seq;
    Frtrans_info  st_trans_info;
    Frreport_body_data *p_st_body_data_req;
    Frreport_body_data *p_st_body_data_resp;
    Frlist_header *p_lst_req_tmp;
    Frlist_header *p_lst_comm_tmp;
    Frbyte_Packet *p_req_packet;                        /* 分片包数据 */
    Frbyte_Packet *p_resp_packet;                       /* 分片包数据 */
    Frbyte_Packet *p_req_data_packet;                   /* 分片包数据 */
    Frbyte_Packet *p_data_packet;                       /* 分片包数据 */
    int i_data_len;                                     /* 响应的数据长度 */
    int i_flag_req_finish;                              /* 请求头解析结束标志(1结束) */
    int i_flag_resp_finish;                             /* 响应头解析结束标志(1结束) */
    int i_flag_need;                                    /* 响应信息是否为需要格式 0:位置 1:上报 2:不上报 */
    int i_flag_data_type;                               /* 0:未知 1:xml 2:json */
    int i_start_pos;                                    /* memstr 起始查询位置 */
    int i_flag_req_report_end;                          /* 请求数据信息上报结束 */
    int i_flag_abandon;
    long l_response_code;
    char *p_code_string;
    char arr_charset[32];
}L7session_http_private;

#define FR_HTTP_LINE_END              "\r\n"
#define HTTP_HEADER_MAX_SIZE           1048576          /* 1M */

extern void *g_p_apm_context;

 /*!
 * 创建L7session_http_private
 *
 * \param void
 *
 * \return NULL      失败\n
 *         p_st_http_private  成功
 *
 * \note
 *
 */
FR_STATIC L7session_http_private* __http_private_create(void)
{
    L7session_http_private *p_st_http_private = NULL;

    //申请内存并初始化
    p_st_http_private = (L7session_http_private*)frmalloc(sizeof(L7session_http_private));
    if (p_st_http_private == NULL)
        return NULL;

    memset(p_st_http_private,'\0',sizeof(L7session_http_private));

    p_st_http_private->p_req_packet = bytebuff_creat();
    if (p_st_http_private->p_req_packet == NULL)
        goto ERROR;

    p_st_http_private->p_resp_packet = bytebuff_creat();
    if (p_st_http_private->p_resp_packet == NULL)
        goto ERROR;

    p_st_http_private->p_req_data_packet = bytebuff_creat();
    if (p_st_http_private->p_req_data_packet == NULL)
        goto ERROR;

    p_st_http_private->p_data_packet = bytebuff_creat();
    if (p_st_http_private->p_data_packet == NULL)
        goto ERROR;

    return p_st_http_private;

ERROR:
    if (p_st_http_private)
    {
        if (p_st_http_private->p_req_packet)
            bytebuff_free(&(p_st_http_private->p_req_packet));
        if (p_st_http_private->p_resp_packet)
            bytebuff_free(&(p_st_http_private->p_resp_packet));
        if (p_st_http_private->p_req_data_packet)
            bytebuff_free(&(p_st_http_private->p_req_data_packet));
        if (p_st_http_private->p_data_packet)
            bytebuff_free(&(p_st_http_private->p_data_packet));

        frfree(p_st_http_private);
    }

    return NULL;
}

/*!
 * 取http请求头信息
 *
 * \param p_tcp_body      (指向体的头)
 * \param ui_tcp_body_len (体的长度)
 * \param pp_uri          (获取uri)
 * \param p_i_uri_len     (获取uri长度)
 * \param p_i_option      (标记位)
 * \param p_st_body_data  (上报数据)
 *
 * \return NULL      不是HTTP\n
 *         != NULL   成功
 *
 * \note
 *
 */
FR_STATIC char * __http_req_header_detect(char *p_tcp_body, unsigned int ui_tcp_body_len, char **pp_uri
                                         , int *p_i_uri_len, int *p_i_option, Frreport_body_data *p_st_body_data)
{
    int i_ret = 0;
    int i_uri_len = 0;
    int i_method_len = 0;
    unsigned int ui_left_len = 0;
    char *p_pos = NULL;
    char *p_uri = NULL;
    const char *p_field_value = NULL;

    if (p_tcp_body == NULL || ui_tcp_body_len == 0)
        return NULL;

    ui_left_len = ui_tcp_body_len;

    //取第一行(Request-Line)
    p_pos = strstr(p_tcp_body , FR_HTTP_LINE_END);
    if (p_pos)
    {
        ui_left_len = p_pos - p_tcp_body;
        if (ui_left_len == 0)
            return NULL;
    }
    else
        return NULL;

    //判断是否符合Request-Line格式(Method SP Request-URI SP HTTP-Version CRLF)
    //请求方法(Method)判断
    p_pos = strchr(p_tcp_body, ' ');
    if (p_pos == NULL)
        return NULL;

    i_method_len = p_pos - p_tcp_body;

    switch (i_method_len)
    {
        case 3:
            if (strncmp(p_tcp_body, "GET ", 4) == 0)
            {
                *p_i_option = 1;
                p_field_value = "GET";
            }
            else if (strncmp(p_tcp_body, "PUT ", 4) == 0)
                p_field_value = "PUT";
            else if (strncmp(p_tcp_body, "ACL ", 4) == 0)
                p_field_value = "ACL";

            break;

        case 4:
            if (strncmp(p_tcp_body, "POST ", 5) == 0 )
            {
                *p_i_option = 2;
                p_field_value = "POST";
            }
            else if (strncmp(p_tcp_body, "HEAD ", 5) == 0)
                p_field_value = "HEAD";
            else if (strncmp(p_tcp_body, "COPY ", 5) == 0)
                p_field_value = "COPY";
            else if (strncmp(p_tcp_body, "MOVE ", 5) == 0)
                p_field_value = "MOVE";
            else if (strncmp(p_tcp_body, "LOCK ", 5) == 0)
                p_field_value = "LOCK";
            else if (strncmp(p_tcp_body, "BIND ", 5) == 0)
                p_field_value = "BIND";
            else if (strncmp(p_tcp_body, "LINK ", 5) == 0)
                p_field_value = "LINK";

            break;

        case 5:
            if (strncmp(p_tcp_body, "TRACE ", 6) == 0)
                p_field_value = "TRACE";
            else if (strncmp(p_tcp_body, "PATCH ", 6) == 0)
                p_field_value = "PATCH";
            else if (strncmp(p_tcp_body, "MKCOL ", 6) == 0)
                p_field_value = "MKCOL";
            else if (strncmp(p_tcp_body, "LABEL ", 6) == 0)
                p_field_value = "LABEL";
            else if (strncmp(p_tcp_body, "MERGE ", 6) == 0)
                p_field_value = "MERGE";

            break;

        case 6:
            if (strncmp(p_tcp_body, "DELETE ", 7) == 0)
                p_field_value = "DELETE";
            else if (strncmp(p_tcp_body, "UNLOCK ", 7) == 0)
                p_field_value = "UNLOCK";
            else if (strncmp(p_tcp_body, "REBIND ", 7) == 0)
                p_field_value = "REBIND";
            else if (strncmp(p_tcp_body, "REPORT ", 7) == 0)
                p_field_value = "REPORT";
            else if (strncmp(p_tcp_body, "SEARCH ", 7) == 0)
                p_field_value = "SEARCH";
            else if (strncmp(p_tcp_body, "UNBIND ", 7) == 0)
                p_field_value = "UNBIND";
            else if (strncmp(p_tcp_body, "UNLINK ", 7) == 0)
                p_field_value = "UNLINK";
            else if (strncmp(p_tcp_body, "UPDATE ", 7) == 0)
                p_field_value = "UPDATE";

            break;

        case 7:
            if (strncmp(p_tcp_body, "OPTIONS ", 8) == 0)
                p_field_value = "OPTIONS";
            else if (strncmp(p_tcp_body, "CHECKIN ", 8) == 0)
                p_field_value = "CHECKIN";

            break;

        case 8:
            if (strncmp(p_tcp_body, "PROPFIND ", 9) == 0)
                p_field_value = "PROPFIND";
            else if (strncmp(p_tcp_body, "CHECKOUT ", 9) == 0)
                p_field_value = "CHECKOUT";

            break;

        case 9:
            if (strncmp(p_tcp_body, "PROPPATCH ", 10) == 0)
                p_field_value = "PROPPATCH";

            break;

        case 10:
            if (strncmp(p_tcp_body, "MKACTIVITY ", 11) == 0)
                p_field_value = "MKACTIVITY";
            else if (strncmp(p_tcp_body, "MKCALENDAR ", 11) == 0)
                p_field_value = "MKCALENDAR";
            else if (strncmp(p_tcp_body, "ORDERPATCH ", 11) == 0)
                p_field_value = "ORDERPATCH";
            else if (strncmp(p_tcp_body, "UNCHECKOUT ", 11) == 0)
                p_field_value = "UNCHECKOUT";

            break;

        case 11:
            if (strncmp(p_tcp_body, "MKWORKSPACE ", 12) == 0)
                p_field_value = "MKWORKSPACE";

            break;

        case 13:
            if (strncmp(p_tcp_body, "MKREDIRECTREF ", 14) == 0)
                p_field_value = "MKREDIRECTREF";

            break;

        case 15:
            if (strncmp(p_tcp_body, "VERSION-CONTROL ", 16) == 0)
                p_field_value = "VERSION-CONTROL";

            break;

        case 16:
            if (strncmp(p_tcp_body, "BASELINE-CONTROL ", 17) == 0)
                p_field_value = "BASELINE-CONTROL";

            break;

        case 17:
            if (strncmp(p_tcp_body, "UPDATEREDIRECTREF ", 18) == 0)
                p_field_value = "UPDATEREDIRECTREF";

            break;

        default:
            return NULL;
    }

    if (p_st_body_data)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.method", p_field_value);
        if (i_ret == FR_FAIL)
            return NULL;
    }
    p_tcp_body += (i_method_len + 1);
    ui_left_len -= (i_method_len + 1);

    //取第2个space
    p_pos = (char*)memchr(p_tcp_body, ' ', ui_left_len);
    if (!p_pos)
        return NULL;

    //获取uri
    if (pp_uri)
    {
        i_uri_len = p_pos - p_tcp_body + 1;
        p_uri = (char*)frmalloc(i_uri_len);
        if (p_uri == NULL)
            return NULL;

        memcpy(p_uri, p_tcp_body, i_uri_len - 1);
        p_uri[i_uri_len - 1] = '\0';
        //设置出例参数
        *pp_uri = p_uri;
        *p_i_uri_len = i_uri_len - 1;
    }

    ui_left_len -= p_pos - p_tcp_body + 1;
    p_tcp_body = p_pos + 1;
    //HTTP-Version格式判定(HTTP/1*DIGIT.1*DIGIT)
    if (strncmp(p_tcp_body, "HTTP/", 5) != 0)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }
    //跳过[HTTP/]
    p_tcp_body += 5;
    ui_left_len -= 5;

    p_pos = (char*)memchr(p_tcp_body, '.', ui_left_len);
    if (p_pos == NULL || p_pos == p_tcp_body)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }
    //判断第一个DIGIT
    for (; p_tcp_body < p_pos; p_tcp_body++)
    {
        if (*p_tcp_body < '0' || *p_tcp_body > '9')
        {
            if (pp_uri)
            {
                frfree(*pp_uri);
                *pp_uri = NULL;
            }
            return NULL;
        }
        else
        {
            ui_left_len--;
        }
    }

    //跳过[.]
    p_tcp_body += 1;
    ui_left_len -= 1;

    //判断第二个DIGIT
    if (ui_left_len == 0)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }

    for (; ui_left_len; ui_left_len--)
    {
        if (*p_tcp_body < '0' || *p_tcp_body > '9')
        {
            if (pp_uri)
            {
                frfree(*pp_uri);
                *pp_uri = NULL;
            }
            return NULL;
        }
        p_tcp_body++;
    }

    p_tcp_body += 2;
    return p_tcp_body;
}

/*!
 * 取http响应头信息
 *
 * \param p_tcp_body      (指向体的头)
 * \param ui_tcp_body_len (体的长度)
 * \param p_st_private    (私有数据)
 *
 * \return NULL     不是HTTP\n
 *         != NULL  成功
 *
 * \note
 *
 */
FR_STATIC char* __http_resp_header_detect(char *p_tcp_body
                                        , unsigned int ui_tcp_body_len
                                        , L7session_http_private *p_st_private)
{
    long l_response_code = 0;
    char *p_pos = NULL;
    char *p_http_info = NULL;
    char *p_response_codestring = NULL;
    char arr_tmp[4];

    if (p_tcp_body == NULL || ui_tcp_body_len == 0)
        return NULL;

    //比较http格式 HTTP/1*DIGIT.1*DIGIT (200 OK)\r\n
    p_http_info = p_tcp_body;
    if (strncasecmp(p_http_info, "HTTP/", 5) != 0)
        return NULL;

    p_http_info += 5;

    p_pos = strchr(p_http_info, '.');
    if (p_pos == NULL || p_pos == p_http_info)
        return NULL;

    for (; p_http_info < p_pos; p_http_info++)
    {
        if (*p_http_info < '0' || *p_http_info > '9')
            return NULL;
    }

    p_http_info = p_pos+1;
    p_pos = strchr(p_http_info, ' ');
    if (p_pos == NULL || p_pos == p_http_info)
        return NULL;

    for (; p_http_info < p_pos; p_http_info++)
    {
        if (*p_http_info < '0' || *p_http_info > '9')
            return NULL;
    }
    p_http_info = p_pos + 1;

    //判断状态码并存取
    if ((p_http_info[0] >= '1' && p_http_info[0] <= '5')
        && (p_http_info[1] >= '0' && p_http_info[1] <= '9')
        && (p_http_info[2] >= '0' && p_http_info[2] <= '9')
        && (p_http_info[3] == ' '))
    {
        p_pos = strstr(p_http_info, FR_HTTP_LINE_END);
        if (p_pos == NULL)
            return NULL;
        //如果不需要取l_response_code p_response_codestring
        if (p_st_private == NULL)
            return p_pos + 2;

        memcpy(arr_tmp, p_http_info, 3);
        arr_tmp[3] = '\0';
        l_response_code = atoi(arr_tmp);

        p_st_private->l_response_code = l_response_code;
        //取p_response_codestring
        if (p_pos - p_http_info - 4 > 0)
        {
            p_response_codestring = (char*)frmalloc(p_pos - p_http_info + 1);
            if (p_response_codestring == NULL)
                return NULL;
            snprintf(p_response_codestring, p_pos - p_http_info + 1, "%s", p_http_info);
            p_st_private->p_code_string = p_response_codestring;
        }

        return p_pos + 2;
    }

    return NULL;
}

/*!
 * 判断是否是TCP协议
 *
 * \param p_st_conn       (输入数据信息)
 * \param p_st_packet     (输入数据)
 *
 * \return APM_L7_IS_YES  属于TCP协议\n
 *         APM_L7_IS_NO   不属于TCP协议
 *
 * \note
 *
 */
int sample_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = 0;
    int i_option = 0;
    char *p_header_tmp = NULL;

    if (p_st_packet == NULL || p_st_conn==NULL)
        return APM_L7_IS_NO;

    //判断是否属于http request
    p_header_tmp = __http_req_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len, NULL, NULL, &i_option, NULL);
    if (p_header_tmp)
    {
        i_ret = frct_get_direct_known(p_st_conn);
        if (i_ret == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);

        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
        return APM_L7_IS_YES;
    }

    //判断是否属于http response
    p_header_tmp = __http_resp_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len, NULL);
    if (p_header_tmp)
    {
        i_ret = frct_get_direct_known(p_st_conn);
        if (i_ret == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);

        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0);
        return APM_L7_IS_YES;
    }

    //如果不能格局特征识别 查询服务器context信息链表
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }

    return APM_L7_IS_NO;
}

/*!
 * 私有信息重置
 *
 * \param p_private_session  (私有数据)
 *
 * \return FR_SUCC  成功\n
 *         FR_FAIL  失败
 *
 * \note
 *
 */
FR_STATIC int __http_session_reset(void **pp_private_session)
{
    L7session_http_private *p_private_http = (L7session_http_private*)*pp_private_session;

    if (p_private_http != NULL)
    {
        //内存释放
        sample_session_destroy(p_private_http);
        p_private_http = __http_private_create();
        if (p_private_http == NULL)
        {
            *pp_private_session = NULL;
            return FR_FAIL;
        }

        if (p_private_http->p_code_string)
        {
            frfree(p_private_http->p_code_string);
            p_private_http->p_code_string = NULL;
        }
    }

    *pp_private_session = p_private_http;

    return FR_SUCC;
}

/*!
 * 取http请求头信息中的字段，存入链表当中
 *
 * \param p_st_private   (私有数据)
 * \param p_packet       (请求数据)
 * \param p_st_body_data (上报数据)
 * \param p_uri          (获取uri)
 * \param p_i_data_len   (获取请求体长度)
 * \param i_pos_start    (起始位置，第二行开头)
 * \param i_pos_end      (终止位置，\r\n\r\n)
 *
 * \return APM_L7_ANALYZE_SUCC  解析结束\n
 *         APM_L7_ANALYZE_FAIL  失败\n
 *         APM_L7_ANALYZE_TODO  数据包格式错误 执行丢包
 *
 * \note
 *
 */
FR_STATIC int __http_req_header_parse(L7session_http_private *p_st_private, Frbyte_Packet *p_packet
                                    , Frreport_body_data *p_st_body_data, char *p_uri
                                    , int *p_i_data_len, int i_pos_start, int i_pos_end)
{
    int i_pos = 0;
    int i_ret = 0;
    int i_pos_tmp = 0;
    int i_name_len = 0;
    int i_value_len = 0;
    char *p_field_name = NULL, *p_field_name_tmp = NULL;
    char *p_value = NULL, *p_value_tmp1 = NULL, *p_value_tmp2 = NULL;

    if (p_st_private == NULL || p_packet == NULL || p_st_body_data == NULL || p_uri == NULL
        || i_pos_start > i_pos_end || i_pos_start < 0)
        goto ERROR;

    i_pos_tmp = i_pos_start;

    //循环取字段名跟值
    while(i_pos_tmp < i_pos_end - 4)
    {
        //获取字段名 格式错误
        if (bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, ":", 1, &i_pos) != FR_SUCC)
        {
            p_st_private->i_flag_abandon = 1;
            p_st_private->i_flag_req_finish = 1;
            return APM_L7_ANALYZE_FAIL;
        }

        //内存分配
        i_name_len = i_pos - i_pos_tmp;
        p_field_name = (char*)frmalloc(i_name_len + 1);
        if (p_field_name == NULL)
            goto ERROR;
        //获取字段名
        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, i_name_len, p_field_name);
        if (i_ret == FR_FAIL)
            goto ERROR;
        p_field_name[i_name_len] = '\0';
        frtrim(p_field_name);

        //转化为小写
        i_ret = frstrlower(p_field_name, i_name_len);
        if (i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            return APM_L7_ANALYZE_FAIL;
        }

        //指向：后一个字符
        i_pos_tmp = i_pos + 1;
        //获取value
        if (bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
            goto ERROR;

        i_value_len = i_pos - i_pos_tmp;
        p_value = (char*)frmalloc(i_value_len + 1);
        if (p_value == NULL)
            goto ERROR;

        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, i_value_len, p_value);
        if (i_ret == FR_FAIL)
            goto ERROR;
        p_value[i_value_len] = '\0';
        frtrim(p_value);
        //p_header_tmp指向下一行
        i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);

        //如果是content
        if (strcasecmp(p_field_name, "Content-Length") == 0)
            *p_i_data_len = atoi(p_value);
        else if (strcasecmp(p_field_name, "Content-Type") == 0)
        {
            //获取charset
            p_value_tmp1 = strstr(p_value, "charset=");
            if (p_value_tmp1 == NULL)
                snprintf(p_st_private->arr_charset, sizeof(p_st_private->arr_charset), "%s", "utf-8");
            else
            {
                //指向内容
                p_value_tmp1 += 8;
                snprintf(p_st_private->arr_charset, sizeof(p_st_private->arr_charset), "%s", p_value_tmp1);
                p_value_tmp1 = strchr(p_st_private->arr_charset, ';');
                if (p_value_tmp1)
                    *p_value_tmp1 = '\0';
                frtrim(p_st_private->arr_charset);
            }
            if (strcasestr(p_value,"xml") != NULL || strcasestr(p_value,"json") != NULL)
                p_st_private->i_flag_need = 1;
            else
                p_st_private->i_flag_need = 2;
        }

        //p_field_name修改
        i_name_len = strlen(p_field_name) + strlen("request.http.header.") + 1;
        p_field_name_tmp = (char*)frmalloc(i_name_len);
        if (p_field_name_tmp == NULL)
            goto ERROR;

        snprintf(p_field_name_tmp, i_name_len, "request.http.header.%s", p_field_name);
        frfree(p_field_name);
        p_field_name = p_field_name_tmp;
        p_field_name_tmp = NULL;

        i_ret = frreport_body_l7_add_str(p_st_body_data, p_field_name, p_value);
        if (i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_field_name);
        frfree(p_value);
        p_field_name = NULL;
        p_value = NULL;
    }

    return APM_L7_ANALYZE_SUCC;

ERROR:
    if (p_field_name_tmp)
        frfree(p_field_name_tmp);
    if (p_field_name)
        frfree(p_field_name);
    if (p_value_tmp1)
        frfree(p_value_tmp1);
    if (p_value_tmp2)
        frfree(p_value_tmp2);
    if (p_value)
        frfree(p_value);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 获取数据
 *
 * \param p_st_private        (私有数据)
 * \param p_st_body_data      (上报数据)
 * \param p_tcp_body          (指向信息头)
 * \param ui_tcp_body_len     (信息长度)
 *
 * \return APM_L7_ANALYZE_SUCC  解析结束\n
 *         APM_L7_ANALYZE_FAIL  解析失败\n
 *         APM_L7_ANALYZE_TODO  解析未完
 *
 * \note
 *
 */
FR_STATIC int __http_req_data_parse(L7session_http_private *p_st_private
                                  , Frreport_body_data *p_st_body_data
                                  , char *p_tcp_body, unsigned int ui_tcp_body_len)
{
    int i_ret = 0;
    int i_header_buff_len = 0;
    char *p_tmp = NULL;
    char *p_header_buff = NULL;
    char arr_head[128];
    Frbyte_Packet *p_packet = NULL;

    if (p_st_private == NULL || p_tcp_body == NULL || p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (ui_tcp_body_len == 0)
        return p_st_private->i_data_len > 0 ? APM_L7_ANALYZE_TODO:APM_L7_ANALYZE_SUCC;

    //除了xml和json不获取数据
    if (p_st_private->i_flag_need == 2)
    {
        p_st_private->i_data_len -= ui_tcp_body_len;
        if (p_st_private->i_data_len > 0)
            return APM_L7_ANALYZE_TODO;
        else
            return APM_L7_ANALYZE_SUCC;
    }

    p_packet = p_st_private->p_req_data_packet;
    if (p_packet == NULL)
        return APM_L7_ANALYZE_FAIL;
    //取得完整的响应数据块
    i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
    if (i_ret != FR_SUCC)
        return APM_L7_ANALYZE_FAIL;

    //获取整个数据块
    i_header_buff_len = bytebuff_length(p_packet);
    if (p_st_private->i_data_len > i_header_buff_len)
        return APM_L7_ANALYZE_TODO;

    p_header_buff = (char*)frmalloc(i_header_buff_len + 1);
    if (p_header_buff == NULL)
        goto ERROR;
    i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_header_buff_len);
    if (i_ret == FR_FAIL)
        goto ERROR;
    p_header_buff[i_header_buff_len] = '\0';

    if (strcasecmp(p_st_private->arr_charset, "utf-8") != 0)
    {
        //将源数据根据其charset转换成UTF8
        i_ret = iconv_to_utf8(p_header_buff, strlen(p_header_buff), p_st_private->arr_charset, &p_tmp, (unsigned int *)&i_header_buff_len);
        if (i_ret != 0)
            goto ERROR;

        frfree(p_header_buff);
        p_header_buff = p_tmp;
        p_tmp = NULL;
    }

    //http.body
    snprintf(arr_head, sizeof(arr_head), "request.http.body");
    i_ret = frreport_body_l7_add_str(p_st_body_data, arr_head, p_header_buff);
        frfree(p_header_buff);

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

ERROR:
    if (p_header_buff)
        frfree(p_header_buff);
    if (p_tmp)
        frfree(p_tmp);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * req解析
 *
 * \param p_st_private        (私有数据)
 * \param p_st_body_data      (上报数据)
 * \param p_tcp_body          (指向信息头)
 * \param ui_tcp_body_len     (信息长度)
 *
 * \return APM_L7_ANALYZE_SUCC  成功\n
 *         APM_L7_ANALYZE_FAIL  失败\n
 *         APM_L7_ANALYZE_TODO  继续解析
 *
 * \note
 *
 */
FR_STATIC int __http_req_parse(L7session_http_private *p_st_private
                                , Frreport_body_data *p_st_body_data
                                , char *p_tcp_body
                                , unsigned int ui_tcp_body_len)
{
    int i_uri_len = 0;
    int i_option = 0;
    int i_pos_start = 0;
    int i_header_buff_len = 0;
    int i_header_tmp_len = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    char *p_uri = NULL;
    char *p_tmp = NULL;
    char *p_header_buff = NULL;
    char *p_header_tmp = NULL;
    char *p_field_value = NULL;
    Frbyte_Packet *p_packet = NULL;

    if (p_st_private == NULL || p_tcp_body == NULL || ui_tcp_body_len == 0 )
        return APM_L7_ANALYZE_FAIL;

    //获取完整的请求体数据头
    p_packet = p_st_private->p_req_packet;
    if (p_packet == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (p_st_private->i_flag_req_finish == 0)
    {
        //如果超过HTTP_HEADER_MAX_SIZE，认为丢包，不解析
        if (p_packet->ui_all_len > HTTP_HEADER_MAX_SIZE)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
        if (i_ret == FR_FAIL)
            goto ERROR;
        //p_header_buff \r\n\r\n
        if (bytebuff_memstr(p_packet, p_st_private->i_start_pos, 0, "\r\n\r\n", strlen("\r\n\r\n"), &i_header_buff_len) != FR_SUCC)
        {
            p_st_private->i_start_pos = p_packet->ui_all_len - 4;
            if (p_st_private->i_start_pos < 0)
                p_st_private->i_start_pos = 0;

            return APM_L7_ANALYZE_TODO;
        }

        p_st_private->i_start_pos = 0;
        i_header_buff_len += 4;

        //取出第一行
        if (bytebuff_memstr(p_packet, 0, i_header_buff_len, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos_start) != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        //指向下一行
        i_pos_start += strlen(FR_HTTP_LINE_END);
        p_header_buff = (char*)frmalloc(i_pos_start + 1);
        if (p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_pos_start);
        if (i_ret == FR_FAIL)
            goto ERROR;
        p_header_buff[i_pos_start] = '\0';
        //解析http请求体 开始行格式判断并指向字段开始行 当返回NULL不是http协议 该情况不存在
        p_header_tmp = __http_req_header_detect(p_header_buff, i_pos_start, &p_uri, &i_uri_len, &i_option, p_st_body_data);
        if (p_header_tmp == NULL)
            goto ERROR;

        frfree(p_header_buff);
        p_header_buff = NULL;

        //get 上报URI
        if (i_option == 1)
        {
            p_tmp = strchr(p_uri,'?');
            if (p_tmp == NULL)
            {
               p_field_value = NULL;
            }
            else
            {
                p_tmp++;
                p_field_value = frstrdup(p_tmp);
                frtrim(p_field_value);
            }

            //get 没有type字段
            if (p_field_value == NULL)
                i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.param.data", "\0");
            else
                i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.param.data", p_field_value);
            if (i_ret == FR_FAIL)
            {
                if (p_field_value)
                    frfree(p_field_value);
                return APM_L7_ANALYZE_FAIL;
            }
            if (p_field_value)
                frfree(p_field_value);

        }

        //获取字段并存入链表当中  直到读到单独空行为止
        i_ret = __http_req_header_parse(p_st_private, p_packet, p_st_body_data, p_uri
                                      , &p_st_private->i_data_len, i_pos_start, i_header_buff_len);

        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        //释放p_uri
        if (p_uri)
        {
            frfree(p_uri);
            p_uri = NULL;
        }

        if (i_ret == APM_L7_ANALYZE_TODO)
            return i_ret;

        //request解析结束
        p_st_private->i_flag_req_finish = 1;

        if (p_st_private->i_data_len > 0)
        {
            if (p_st_private->i_flag_need == 2)
            {
                p_st_private->i_data_len -= (bytebuff_length(p_packet) - i_header_buff_len);
                if (p_st_private->i_data_len > 0)
                    i_ret = APM_L7_ANALYZE_TODO;
                else
                    i_ret = APM_L7_ANALYZE_SUCC;
            }
            else
            {
                //存req data
                i_header_tmp_len = bytebuff_length(p_packet) - i_header_buff_len;
                p_header_tmp = (char*)frmalloc(i_header_tmp_len + 1);
                i_ret = bytebuff_get_bytes_at( p_packet, i_header_buff_len, i_header_tmp_len, p_header_tmp);
                if (i_ret == FR_FAIL)
                    goto ERROR;
                p_header_tmp[i_header_tmp_len] = '\0';

                i_ret = __http_req_data_parse(p_st_private, p_st_body_data, p_header_tmp, i_header_tmp_len);
                frfree(p_header_tmp);
                p_header_tmp = NULL;
            }
        }

        return i_ret;
    }

    i_ret = __http_req_data_parse(p_st_private, p_st_body_data, p_tcp_body, ui_tcp_body_len);

    return i_ret;

ERROR:
    if (p_uri)
        frfree(p_uri);
    if (p_header_buff)
        frfree(p_header_buff);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 取http响应头信息中的字段，存入链表当中兵并跳过数据
 *
 * \param p_packet       (resp数据)
 * \param p_st_body_data (上报数据)
 * \param p_i_data_len   (resp数据长度)
 * \param p_st_private   (私有数据)
 * \param i_pos_start    (起始位置，第二行开头)
 * \param i_pos_end      (终止位置，\r\n\r\n)
 *
 * \return APM_L7_ANALYZE_SUCC  解析结束\n
 *         APM_L7_ANALYZE_FAIL  失败\n
 *         APM_L7_ANALYZE_TODO  数据包格式错误 执行丢包
 *
 * \note
 *
 */
FR_STATIC int __http_resp_header_parse(Frbyte_Packet *p_packet, Frreport_body_data *p_st_body_data
                                , int *p_i_data_len, L7session_http_private *p_st_private
                                , int i_pos_start, int i_pos_end)
{
    int i_ret = 0;
    int i_pos = 0;
    int i_value_len = 0;
    int i_name_len = 0;
    int i_pos_tmp = i_pos_start;
    char *p_value = NULL;
    char *p_value_tmp1 = NULL;
    char *p_value_tmp2 = NULL;
    char *p_field_name = NULL;
    char *p_field_name_tmp = NULL;

    if (p_packet == NULL || p_st_body_data == NULL || p_st_private == NULL
        || p_i_data_len == NULL || i_pos_start > i_pos_end || i_pos_start < 0)
        return APM_L7_ANALYZE_FAIL;

    while(i_pos_tmp < i_pos_end - 4)
    {
        //p_header_inf内存申请
        //获取字段名
        if (bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, ":", 1, &i_pos) != FR_SUCC)
        {
            p_st_private->i_flag_abandon = 1;
            return APM_L7_ANALYZE_TODO;
        }

        i_name_len = i_pos - i_pos_tmp;
        //获取字段名并 ':'--> '\0'
        p_field_name = (char*)frmalloc(i_name_len + 1);
        if (p_field_name == NULL)
            goto ERROR;
        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, i_name_len, p_field_name);
        if (i_ret == FR_FAIL)
            goto ERROR;
        p_field_name[i_name_len] = '\0';
        frtrim(p_field_name);

        //转化为小写
        i_ret = frstrlower(p_field_name, i_name_len);
        if (i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            return APM_L7_ANALYZE_FAIL;
        }

        //指向：后一个字符
        i_pos_tmp = i_pos + 1;
        //获取value
        if (bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
            goto ERROR;

        i_value_len = i_pos - i_pos_tmp;
        p_value = (char*)frmalloc(i_value_len + 1);
        if (p_value == NULL)
            goto ERROR;

        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, i_value_len, p_value);
        if (i_ret == FR_FAIL)
            goto ERROR;
        p_value[i_value_len] = '\0';
        frtrim(p_value);
        //p_header_tmp指向下一行
        i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);

        //如果是Content-Length，则存下Content-Length
        if (strcasecmp(p_field_name, "Content-Length") == 0)
            *p_i_data_len = atoi(p_value);
        //判断Content-Type
        else if (strcasecmp(p_field_name, "Content-Type") == 0)
        {
            if (strcasestr(p_value,"xml") != NULL)
            {
                p_st_private->i_flag_data_type = 1;
                p_st_private->i_flag_need = 1;
            }
            else if (strcasestr(p_value,"json") != NULL)
            {
                p_st_private->i_flag_data_type = 2;
                p_st_private->i_flag_need = 1;
            }
            else
            {
                p_st_private->i_flag_data_type = 0;
                p_st_private->i_flag_need = 2;
            }
        }

        //p_field_name修改
        i_name_len = strlen(p_field_name) + strlen("response.http.header.") + 1;
        p_field_name_tmp = (char*)frmalloc(i_name_len);
        if (p_field_name_tmp == NULL)
            goto ERROR;

        snprintf(p_field_name_tmp, i_name_len, "response.http.header.%s", p_field_name);
        frfree(p_field_name);
        p_field_name = p_field_name_tmp;
        p_field_name_tmp = NULL;

        //存到结构体中
        i_ret = frreport_body_l7_add_str(p_st_body_data, p_field_name, p_value);
        if (i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_field_name);
        frfree(p_value);
        p_field_name = NULL;
        p_value = NULL;
    }

    return APM_L7_ANALYZE_SUCC;

ERROR:
    if (p_field_name)
        frfree (p_field_name);

    if (p_value)
        frfree(p_value);
    if (p_value_tmp1)
        frfree(p_value_tmp1);
     if (p_value_tmp2)
        frfree(p_value_tmp2);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 获取数据
 *
 * \param p_st_private        (私有数据)
 * \param p_st_body_data      (上报数据)
 * \param p_tcp_body          (指向信息头)
 * \param ui_tcp_body_len     (信息长度)
 *
 * \return APM_L7_ANALYZE_SUCC  解析结束\n
 *         APM_L7_ANALYZE_FAIL  解析失败\n
 *         APM_L7_ANALYZE_TODO  解析未完
 *
 * \note
 *
 */
FR_STATIC int __http_resp_data_parse(L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, char *p_tcp_body, unsigned int ui_tcp_body_len)
{
    int i_ret = 0;
    int i_header_buff_len = 0;
    char *p_header_buff = NULL;
    char arr_head[128];
    Frbyte_Packet *p_packet = NULL;

    if (p_st_private == NULL || p_tcp_body == NULL || p_st_body_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (ui_tcp_body_len == 0)
        return p_st_private->i_data_len > 0 ? APM_L7_ANALYZE_TODO:APM_L7_ANALYZE_SUCC;

    //获取所需要的数据
    if (p_st_private->i_flag_need == 1)
    {
        p_packet = p_st_private->p_data_packet;
        if (p_packet == NULL)
            return APM_L7_ANALYZE_FAIL;

        //取得完整的响应数据块
        i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
        if (i_ret != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        //判断是否结束
        i_header_buff_len = bytebuff_length(p_packet);
        if (p_st_private->i_data_len > i_header_buff_len)
            return APM_L7_ANALYZE_TODO;

        //获取整个数据块
        p_header_buff = (char*)frmalloc(i_header_buff_len + 1);
        if (p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;
        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_header_buff_len);
        if (i_ret == FR_FAIL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        p_header_buff[i_header_buff_len] = '\0';

        if (p_st_private->i_flag_data_type == 1 || p_st_private->i_flag_data_type == 2)
        {
            //字段名
            snprintf(arr_head, sizeof(arr_head), "response.http.body");
            i_ret = frreport_body_l7_add_str(p_st_private->p_st_body_data_resp, arr_head, p_header_buff);
            if (i_ret == FR_FAIL)
            {
                frfree(p_header_buff);
                return APM_L7_ANALYZE_FAIL;
            }
            frfree(p_header_buff);
        }
        else
            frfree(p_header_buff);

        return APM_L7_ANALYZE_SUCC;
    }
    else
    {
        if ((unsigned int)p_st_private->i_data_len > ui_tcp_body_len)
        {
            p_st_private->i_data_len -= ui_tcp_body_len;
            return APM_L7_ANALYZE_TODO;
        }
        else
            return APM_L7_ANALYZE_SUCC;
    }
}

/*!
 * resp解析
 *
 * \param p_st_private        (私有数据)
 * \param p_st_body_data      (上报数据)
 * \param p_tcp_body          (指向信息头)
 * \param ui_tcp_body_len     (信息长度)
 *
 * \return APM_L7_ANALYZE_SUCC  成功\n
 *         APM_L7_ANALYZE_FAIL  失败\n
 *         APM_L7_ANALYZE_TODO  继续解析
 *
 * \note
 *
 */
FR_STATIC int __http_resp_parse(L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data
                              , char *p_tcp_body, unsigned int ui_tcp_body_len)
{
    int i_ret = 0;
    int i_pos_start = 0;
    int i_header_buff_len = 0;
    int i_header_tmp_len = 0;
    char *p_header_buff = NULL;
    char *p_header_tmp = NULL;
    Frbyte_Packet *p_packet = NULL;

    if (p_st_private == NULL || p_tcp_body == NULL || ui_tcp_body_len == 0)
        return APM_L7_ANALYZE_FAIL;

    //获取字段并存入链表当中
    if (p_st_private->i_flag_resp_finish == 0)
    {
        //获取完整的请求体数据头
        p_packet = p_st_private->p_resp_packet;
        if (p_packet == NULL)
            return APM_L7_ANALYZE_FAIL;

        //如果超过HTTP_HEADER_MAX_SIZE 则认为丢包 不解析
        if (p_packet->ui_all_len > HTTP_HEADER_MAX_SIZE)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
        if (i_ret == FR_FAIL)
            goto ERROR;

        //\r\n\r\n
        if (bytebuff_memstr(p_packet, p_st_private->i_start_pos, 0, "\r\n\r\n", strlen("\r\n\r\n"), &i_header_buff_len) != FR_SUCC)
        {
            p_st_private->i_start_pos = p_packet->ui_all_len - 4;
            if (p_st_private->i_start_pos < 0)
                p_st_private->i_start_pos = 0;

            return APM_L7_ANALYZE_TODO;
        }

        p_st_private->i_start_pos = 0;
        i_header_buff_len += 4;

        //取出第一行
        if (bytebuff_memstr(p_packet, 0, i_header_buff_len, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos_start) != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        //指向下一行
        i_pos_start += strlen(FR_HTTP_LINE_END);
        p_header_buff = (char*)frmalloc(i_pos_start + 1);
        if (p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;

        //p_header_buff保存第一行
        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, i_pos_start);
        if (i_ret == FR_FAIL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        p_header_buff[i_pos_start] = '\0';
        //取出resp code和code string
        p_header_tmp = __http_resp_header_detect(p_header_buff, i_pos_start, p_st_private);
        if (p_header_tmp == NULL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_header_buff);
        p_header_buff = NULL;
        p_header_tmp = NULL;

        //跳过\r\n
        i_header_tmp_len = i_pos_start;

        //解析头信息
        i_ret = __http_resp_header_parse(p_packet, p_st_body_data, &p_st_private->i_data_len, p_st_private, i_header_tmp_len, i_header_buff_len);
        if (i_ret == APM_L7_ANALYZE_TODO)
            return APM_L7_ANALYZE_TODO;

        //刚好解析完成
        if (i_ret == APM_L7_ANALYZE_SUCC)
        {
            p_st_private->i_flag_resp_finish = 1;
            //存取响应数据
            if (p_st_private->i_data_len == 0)
                return APM_L7_ANALYZE_SUCC;

            //存取resp data
            i_header_tmp_len = (bytebuff_length(p_packet) - i_header_buff_len);
            p_header_tmp = (char*)frmalloc(i_header_tmp_len + 1);
            if (p_header_tmp == NULL)
                goto ERROR;
            i_ret = bytebuff_get_bytes_at(p_packet, i_header_buff_len, i_header_tmp_len, p_header_tmp);
            if (i_ret == FR_FAIL)
                goto ERROR;
            p_header_tmp[i_header_tmp_len] = '\0';
            i_ret = __http_resp_data_parse(p_st_private, p_st_body_data, p_header_tmp,i_header_tmp_len);
            frfree(p_header_tmp);
            p_header_tmp = NULL;
            return i_ret;

        }
    }
    else
    {
        //存取响应数据或者丢包 纯数据
        i_ret = __http_resp_data_parse(p_st_private, p_st_body_data, p_tcp_body,ui_tcp_body_len);
        return i_ret;
    }

ERROR:
    if (p_header_tmp)
        frfree(p_header_tmp);
    if (p_packet)
    {
        bytebuff_free(&p_packet);
        p_st_private->p_resp_packet = bytebuff_creat();
    }

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * http的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet        (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 *
 * \return APM_L7_ANALYZE_SUCC  成功\n
 *         APM_L7_ANALYZE_FAIL  失败\n
 *         APM_L7_ANALYZE_TODO  数据包未完整
 *
 * \note
 *
 */
int sample_analysis(Conntrack *p_st_conn
                , Apm_packet *p_st_packet
                , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    unsigned long ul_tmp = 0;
    unsigned int ui_tcp_body_len = 0;
    char *p_tcp_body = NULL;
    L7_session *p_st_session = NULL;
    L7session_http_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_tcp_body = p_st_packet->p_payload;
    ui_tcp_body_len = p_st_packet->ui_payload_len;

    //到Conntrack中取得session信息
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //获取private
    if (p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __http_private_create();
        if (p_st_session->p_session_private == NULL)
            goto ERROR;
    }

    p_st_private = (L7session_http_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    //fin syn
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        sample_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //request
    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        //如果连续两个request数据则销毁上一次生成的私有数据
        if (p_st_private->i_flag_req_report_end == 1)
        {
            if (__http_session_reset((void **)(&p_st_session->p_session_private)) == FR_FAIL)
                goto ERROR;
            p_st_private = (L7session_http_private *)p_st_session->p_session_private;
            p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);
        }

        //首包时间
        if (p_st_l4_trans->st_request_time_first_byte.tv_sec == 0 && p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
        {
            //第一个包 st_request_time_first_byte
            if (p_st_private->p_st_body_data_req == NULL)
            {
                p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
                if (p_st_private->p_st_body_data_req == NULL)
                    goto ERROR;

                i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn);
                if (i_ret == FR_FAIL)
                    goto ERROR;
            }

            p_st_private->ul_seq = frct_seq_increase(p_st_conn);

            if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
                goto ERROR;

            if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
                goto ERROR;

            if (frreport_body_l7_add_int(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
                goto ERROR;

            p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        }
        p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
        //请求的字节数
        p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

        i_ret = __http_req_parse(p_st_private, p_st_private->p_st_body_data_req, p_tcp_body, ui_tcp_body_len);
        if (i_ret == APM_L7_ANALYZE_SUCC)
        {
            //request_time_us
            ul_tmp = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &p_st_packet->st_timestamp);
            if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
                goto ERROR;

            //响应字节数
            if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
                goto ERROR;

            if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
                goto ERROR;

            //数据上报
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
            if (p_st_report_data == NULL)
                goto ERROR;

            //保存req数据
            p_st_private->p_lst_req_tmp = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
            if (p_st_private->p_lst_req_tmp == NULL)
                goto ERROR;

            //保存conn数据
            p_st_private->p_lst_comm_tmp = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_private->p_st_body_data_req);
            if (p_st_private->p_lst_comm_tmp == NULL)
                goto ERROR;

            if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
                goto ERROR;
            p_st_private->p_st_body_data_req = NULL;

            if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            {
                frreport_data_free(&p_st_report_data);
                goto ERROR;
            }
            p_st_report_data = NULL;

            //req数据上报结束
            p_st_private->i_flag_req_finish = 0;
            p_st_private->i_flag_req_report_end = 1;
            return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
        }

        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }

    //response
    if (p_st_packet->i_direction == FR_DIRECT_SRV2CLIENT)
    {
        //首包时间
        if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
        {
            //应答发起时间戳
            p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
            if (p_st_private->p_st_body_data_resp == NULL)
                goto ERROR;

            p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

            if (p_st_l4_trans->st_request_time_first_byte.tv_sec)
            {
                //comm
                if (FRREPORT_BODY_L7LIST_SET_COMM(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_comm_tmp) == FR_FAIL)
                    goto ERROR;

                //把req数据链表添加到resp中
                if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req_tmp) == FR_FAIL)
                    goto ERROR;

                //server_time_us
                ul_tmp = frtime_diff(&p_st_l4_trans->st_request_time, &p_st_l4_trans->st_response_time_first_byte);
                if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
                    goto ERROR;
            }
            else
            {
                i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn);
                if (i_ret == FR_FAIL)
                    goto ERROR;
            }

            if (p_st_private->ul_seq == 0)
            {
                p_st_private->ul_seq = frct_seq_increase(p_st_conn);
                if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
                    goto ERROR;
            }

            if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
                goto ERROR;

        }

        p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
        //响应的字节数
        p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

        i_ret = __http_resp_parse(p_st_private, p_st_private->p_st_body_data_resp, p_tcp_body, ui_tcp_body_len);

        if (i_ret == APM_L7_ANALYZE_SUCC)
        {
            if (p_st_private->ul_seq == 0)
                p_st_private->ul_seq = frct_seq_increase(p_st_conn);

            if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
                goto ERROR;

            if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
                goto ERROR;

            ul_tmp = frtime_diff(&p_st_l4_trans->st_response_time_first_byte, &p_st_l4_trans->st_response_time);
            if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
                goto ERROR;

            if (p_st_l4_trans->st_request_time_first_byte.tv_sec)
                p_st_l4_trans->ul_response_time_us = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_packet->st_timestamp));
            else
            {
                if (__http_session_reset((void **)(&p_st_session->p_session_private)) == FR_FAIL)
                {
                    sample_session_destroy((void *)(p_st_session->p_session_private));
                    p_st_session->p_session_private = NULL;
                }

                return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }

            //resp code 上报
            i_ret = frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE, p_st_private->l_response_code);
            if (i_ret == FR_FAIL)
                goto ERROR;

            //resp code string 上报
            i_ret = frreport_body_l7_add_str(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE_STRING, p_st_private->p_code_string);
            if (i_ret == FR_FAIL)
                goto ERROR;

            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
            if (p_st_report_data == NULL)
                goto ERROR;

            //resp 数据上报
            if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
                goto ERROR;
            p_st_private->p_st_body_data_resp = NULL;

            if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            {
                frreport_data_free(&p_st_report_data);
                goto ERROR;
            }
            p_st_report_data = NULL;

            if (__http_session_reset((void **)(&p_st_session->p_session_private)) == FR_FAIL)
            {
                sample_session_destroy((void *)(p_st_session->p_session_private));
                p_st_session->p_session_private = NULL;
            }

            return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
        }

        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }

ERROR:
    if (p_st_session->p_session_private)
    {
        sample_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
    }

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 私有信息销毁
 *
 * \param p_private_session       (http的私有session数据)
 *
 * \return FR_SUCC  完成
 *
 * \note
 *
 */
int sample_session_destroy(void *p_private_session)
{
    L7session_http_private *p_private_http = (L7session_http_private*)p_private_session;
    L7_transaction *p_st_l7_trans = NULL;

    if (p_private_http != NULL)
    {
        //内存释放
        if (p_private_http->p_lst_req_tmp)
            frreport_body_l7list_free(&p_private_http->p_lst_req_tmp);

        //p_lst_comm_tmp
        if (p_private_http->p_lst_comm_tmp)
            frreport_body_l7list_free(&p_private_http->p_lst_comm_tmp);

        if (p_private_http->p_st_body_data_req)
            frreport_body_free(&p_private_http->p_st_body_data_req);

        if (p_private_http->p_st_body_data_resp)
            frreport_body_free(&p_private_http->p_st_body_data_resp);

        bytebuff_free(&(p_private_http->p_req_packet));
        bytebuff_free(&(p_private_http->p_resp_packet));
        bytebuff_free(&(p_private_http->p_req_data_packet));
        bytebuff_free(&(p_private_http->p_data_packet));

        if (p_private_http->p_code_string)
        {
            frfree(p_private_http->p_code_string);
            p_private_http->p_code_string = NULL;
        }

        p_st_l7_trans = &p_private_http->st_trans_info.st_l7_trans;

        if (p_st_l7_trans->p_response_codestring)
            frfree(p_st_l7_trans->p_response_codestring);

        frfree(p_private_session);
    }
    return FR_SUCC;
}
